using DapperExtensionsNew.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace DapperExtensionsNew.Queryable
{
	public class Compiler
	{
		private static readonly MethodInfo GetWhereMethodInfo = typeof(Compiler).GetMethod("GetWhere", BindingFlags.Static | BindingFlags.NonPublic);

		public Func<IQuery<TModel>, Clause> Compile<TModel>(Type typeOfQuery)
		{
			Type typeFromHandle = typeof(TModel);
			ParameterExpression parameterExpression = Expression.Variable(typeof(Clause), "clause");
			ParameterExpression parameterExpression2 = Expression.Variable(typeof(StringBuilder), "where");
			ParameterExpression parameterExpression3 = Expression.Variable(typeof(string), "order");
			ParameterExpression parameterExpression4 = Expression.Variable(typeof(DynanicParameters), "parameters");
			ParameterExpression parameterExpression5 = Expression.Variable(typeOfQuery, "concreteQuery");
			ParameterExpression parameterExpression6 = Expression.Parameter(typeof(IQuery<TModel>), "query");
			IList<Expression> list = new List<Expression>();
			list.Add(Expression.Assign(parameterExpression5, Expression.Convert(parameterExpression6, typeOfQuery)));
			list.Add(Expression.Assign(parameterExpression, Expression.New(typeof(Clause))));
			list.Add(Expression.Assign(parameterExpression4, Expression.New(typeof(DynanicParameters))));
			list.Add(Expression.Assign(parameterExpression2, Expression.New(typeof(StringBuilder))));
			list.Add(Expression.Assign(parameterExpression3, Expression.Constant(string.Empty)));
			IAnalyzer[] array = CreateAnalyzer(typeFromHandle);
			if (array != null && array.Any())
			{
				Context context = new Context(parameterExpression2, parameterExpression4, parameterExpression3, parameterExpression5, typeFromHandle, typeOfQuery);
				IAnalyzer[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i].Analyze(context);
				}
				IList<Expression> statements = context.Statements;
				if (statements.Any())
				{
					list.Add(Expression.Block(statements));
				}
			}
			LabelTarget target = Expression.Label(typeof(Clause));
			PropertyInfo property = typeof(Clause).GetProperty("Where") ?? throw new InvalidOperationException();
			BinaryExpression item = Expression.Assign(Expression.Property(parameterExpression, property), Expression.Call(null, GetWhereMethodInfo, parameterExpression2));
			list.Add(item);
			PropertyInfo property2 = typeof(Clause).GetProperty("OrderBy") ?? throw new InvalidOperationException();
			BinaryExpression item2 = Expression.Assign(Expression.Property(parameterExpression, property2), parameterExpression3);
			list.Add(item2);
			PropertyInfo property3 = typeof(Clause).GetProperty("Parameters") ?? throw new InvalidOperationException();
			BinaryExpression item3 = Expression.Assign(Expression.Property(parameterExpression, property3), parameterExpression4);
			list.Add(item3);
			GotoExpression item4 = Expression.Return(target, parameterExpression);
			LabelExpression item5 = Expression.Label(target, Expression.Default(typeof(Clause)));
			list.Add(item4);
			list.Add(item5);
			return Expression.Lambda<Func<IQuery<TModel>, Clause>>(Expression.Block(new ParameterExpression[5]
			{
				parameterExpression,
				parameterExpression4,
				parameterExpression2,
				parameterExpression3,
				parameterExpression5
			}, list), new ParameterExpression[1]
			{
				parameterExpression6
			}).Compile();
		}

		private static IAnalyzer[] CreateAnalyzer(Type typeOfModel)
		{
			return AnalyzerFactory.GetAnalyzer(TableCache.GetTable(typeOfModel).Analyzer);
		}

		private static string GetWhere(StringBuilder sb)
		{
			string text = sb.ToString();
			text = text.Trim();
			if (text.StartsWith("AND"))
			{
				text = text.Substring(3);
			}
			if (text.Length <= 0)
			{
				return string.Empty;
			}
			return " WHERE " + text;
		}
	}
}
